// 2015年版权所有etcd作者
// 
// 根据Apache许可证2.0版（以下简称“许可证”）获得许可；
// 除非遵守许可证，否则不得使用此文件。
// 您可以通过
// 
// www.apache.org/licenses/LICENSE-2.0 
// 
// 除非适用法律要求或书面同意，否则根据许可证分发的软件
// 按“原样”分发，
// 无任何明示或暗示的保证或条件。
// 请参阅许可证，了解管理许可的特定语言和
// 许可证下的限制。

package v2store

import (
	"sort"
	"time"

	"github.com/jonboulle/clockwork"
)

// 当其他模块调用v2存储的Storage接口获取节点数据时，v2存储并不会直接将相应的node实例暴露出去，
// 而是会将node实例封装成Nod巳Extern实例之后再返回。结构体NodeExtem中除了包含node中的核心数据，还包含了一些扩展宇段，
type NodeExtern struct {
	// 对应node实例中的Path字段。为了实现排序功能，NodeExtem实现了so口接口
	// ，在其Less（）方法实现中比较的就是Key宇段。
	Key           string      `json:"key,omitempty"`
	// 对应键值对节点中的Value字段。
	Value         *string     `json:"value,omitempty"`
	// 对应节点是否为目录节点。
	Dir           bool        `json:"dir,omitempty"`
	// 对应节点的过期时间。如果对应节点是“永久节点”，则该字段值为nil。
	Expiration    *time.Time  `json:"expiration,omitempty"`
	// 对应节点的剩余存活时间，单位是秒。如果对应节点是“永久节点”，则该字段值为0。
	TTL           int64       `json:"ttl,omitempty"`
	// 子节点对应的Nod巳Extern实例。
	Nodes         NodeExterns `json:"nodes,omitempty"`
	// 对应节点的Modifiedlndex宇段值。
	ModifiedIndex uint64      `json:"modifiedIndex,omitempty"`
	// 对应节点的Createdlndex字段值。
	CreatedIndex  uint64      `json:"createdIndex,omitempty"`
}

func (eNode *NodeExtern) loadInternalNode(n *node, recursive, sorted bool, clock clockwork.Clock) {
	if n.IsDir() { // 节点是目录
		eNode.Dir = true

		children, _ := n.List()
		eNode.Nodes = make(NodeExterns, len(children))

		// 我们不在子切片中使用索引直接
		// 我们需要跳过隐藏的一个
		i := 0

		for _, child := range children {
			if child.IsHidden() { // get不会返回隐藏节点
				continue
			}

			eNode.Nodes[i] = child.Repr(recursive, sorted, clock)
			i++
		}

		// 消除隐藏节点
		eNode.Nodes = eNode.Nodes[:i]

		if sorted {
			sort.Sort(eNode.Nodes)
		}

	} else { // 节点是文件
		value, _ := n.Read()
		eNode.Value = &value
	}

	eNode.Expiration, eNode.TTL = n.expirationAndTTL(clock)
}

func (eNode *NodeExtern) Clone() *NodeExtern {
	if eNode == nil {
		return nil
	}
	nn := &NodeExtern{
		Key:           eNode.Key,
		Dir:           eNode.Dir,
		TTL:           eNode.TTL,
		ModifiedIndex: eNode.ModifiedIndex,
		CreatedIndex:  eNode.CreatedIndex,
	}
	if eNode.Value != nil {
		s := *eNode.Value
		nn.Value = &s
	}
	if eNode.Expiration != nil {
		t := *eNode.Expiration
		nn.Expiration = &t
	}
	if eNode.Nodes != nil {
		nn.Nodes = make(NodeExterns, len(eNode.Nodes))
		for i, n := range eNode.Nodes {
			nn.Nodes[i] = n.Clone()
		}
	}
	return nn
}

type NodeExterns []*NodeExtern

// 用于排序

func (ns NodeExterns) Len() int {
	return len(ns)
}

func (ns NodeExterns) Less(i, j int) bool {
	return ns[i].Key < ns[j].Key
}

func (ns NodeExterns) Swap(i, j int) {
	ns[i], ns[j] = ns[j], ns[i]
}
